﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using System.Text;
using System.Xml.XPath;

namespace Utils
{
    /// <summary>
    /// This class transforms a XML file in an XLST file
    /// </summary>
    public class XSLTTransformer
    {
        private XmlDocument m_objXMLDoc;
        private XslTransform m_objXSLTransform;
        private static readonly XSLTTransformer objXSLTTransformer = new XSLTTransformer();

        /// <summary>
        /// Get only one instance of the current class
        /// </summary>
        /// <returns></returns>
        public static XSLTTransformer Instance
        {
            get
            {
                return objXSLTTransformer;
            }
        }

        /// <summary>
        /// Constructor
        /// </summary>
        public XSLTTransformer()
        {
            m_objXMLDoc = new XmlDocument();
            m_objXSLTransform = new XslTransform();
        }

        /// <summary>
        /// With an XmlDocument
        /// </summary>
        /// <param name="input">input</param>
        public void setXML(XmlDocument input)
        {
            m_objXMLDoc = input;
        }

        /// <summary>
        /// With an input stream
        /// </summary>
        /// <param name="input">input</param>
        public void setXML(Stream input)
        {
            if (input != null)
                m_objXMLDoc.Load(input);
        }

        /// <summary>
        /// With an XML reader
        /// </summary>
        /// <param name="reader">reader</param>
        public void setXML(XmlReader reader)
        {
            if (reader != null)
                m_objXMLDoc.Load(reader);
        }

        /// <summary>
        /// With a plain string
        /// </summary>
        /// <param name="strXML">strXML</param>
        public void setXML(string strXML)
        {
            if (strXML.Length > 0)
                m_objXMLDoc.LoadXml(strXML);
        }

        /// <summary>
        /// Get the string of the XML
        /// </summary>
        /// <returns>XML text</returns>
        public string getXML()
        {
            if (m_objXMLDoc != null)
                return m_objXMLDoc.InnerXml;
            else
                return null;
        }

        /// <summary>
        /// With a plain stringpath
        /// </summary>
        /// <param name="strXMLPath">XML Path</param>
        public void setXSL(string strXMLPath)
        {
            if (strXMLPath.Length > 0)
                m_objXSLTransform.Load(strXMLPath);
        }

        /// <summary>
        /// With an XmlDocument instance
        /// </summary>
        /// <param name="xsl">Xml Document Object</param>
        public void setXSL(XmlDocument xsl)
        {
            m_objXSLTransform.Load(xsl.DocumentElement.CreateNavigator());
        }

        /// <summary>
        /// With TextWriter
        /// </summary>
        /// <param name="output">output TextWriter object</param>
        public void Transform(System.IO.TextWriter output)
        {
            try
            {
                XPathNavigator navigator = m_objXMLDoc.DocumentElement.CreateNavigator();
                XmlTextWriter writer = new XmlTextWriter(output);
                m_objXSLTransform.Transform(navigator, null, writer);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Get the string result
        /// </summary>
        /// <returns></returns>
        public string TransformToString()
        {
            StringBuilder sb = new StringBuilder();
            try
            {
                XPathNavigator navigator = m_objXMLDoc.DocumentElement.CreateNavigator();

                using (StringWriter swriter = new StringWriter(sb))
                {
                    XmlTextWriter writer = new XmlTextWriter(swriter);
                    writer.Formatting = Formatting.Indented;
                    writer.Indentation = 4;

                    m_objXSLTransform.Transform(navigator, null, writer);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return sb.ToString();
        }

        /// <summary>
        /// Transforms the supplied xml using the supplied xslt and returns the
        /// result of the transformation
        /// </summary>
        /// <param name="xml">The xml to be transformed</param>
        /// <param name="xslt">The xslt to transform the xml</param>
        /// <returns>The transformed xml</returns>
        public string TransformXml(string xml, string xslt)
        {
            // Simple data checks
            if (string.IsNullOrEmpty(xml))
                throw new ArgumentException("Param cannot be null or empty", "xml");

            if (string.IsNullOrEmpty(xslt))
                throw new ArgumentException("Param cannot be null or empty", "xslt");

            string xmlValue = string.Empty;
            try
            {
                // Create required readers for working with xml and xslt
                using (StringReader xsltInput = new StringReader(xslt))
                {
                    using (StringReader xmlInput = new StringReader(xml))
                    {
                        XmlTextReader xsltReader = new XmlTextReader(xsltInput);
                        XmlTextReader xmlReader = new XmlTextReader(xmlInput);

                        // Create required writer for output
                        using (StringWriter stringWriter = new StringWriter())
                        {
                            XmlTextWriter transformedXml = new XmlTextWriter(stringWriter);

                            // Create a XslCompiledTransform to perform transformation
                            XslCompiledTransform xsltTransform = new XslCompiledTransform();

                            xsltTransform.Load(xsltReader, new XsltSettings(true, true), null);
                            xsltTransform.Transform(xmlReader, transformedXml);
                            xmlValue = stringWriter.ToString();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return xmlValue;
        }
    }
}